// ------------------------------------------------------------------------------------------
// Licensed by Interprise Solutions.
// http://www.InterpriseSolutions.com
// For details on this license please visit  the product homepage at the URL above.
// THE ABOVE NOTICE MUST REMAIN INTACT.
// ------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Web;
using System.Data;
using System.Data.SqlClient;

namespace InterpriseSuiteEcommerceCommon.InterpriseIntegration.Web
{
    public class DownloadableItem
    {
        #region Variable Declaration

        private const int ID_LENGTH = 10;
        private string _itemCode = string.Empty;
        private string _downloadId = string.Empty;
        private string _contentType = string.Empty;
        private string _fileName = string.Empty;
        private string _extension = string.Empty;
        private bool _isActive = false;
        private long _contentLength = 0;

        #endregion

        #region Constructor
        public DownloadableItem()
        {
        }

        public DownloadableItem(string itemCode,
            string downloadId,
            string fileName,
            string extension,
            string contentType,
            long contentLength,
            bool isActive)
        {
            _itemCode = itemCode;
            _downloadId = downloadId;
            _fileName = fileName;
            _contentType = contentType;
            _extension = extension;
            _contentLength = contentLength;
            _isActive = isActive;
        }
        #endregion

        #region Properties

        public string ItemCode
        {
            get { return _itemCode; }
            set { _itemCode = value; }
        }

        public string DownloadId
        {
            get { return _downloadId; }
            set { _downloadId = value; }
        }

        public string FileName
        {
            get { return _fileName; }
            set { _fileName = value; }
        }

        public string Extension
        {
            get { return _extension; }
            set { _extension = value; }
        }

        public string ContentType
        {
            get { return _contentType; }
            set { _contentType = value; }
        }

        public bool IsActive
        {
            get { return _isActive; }
            set { _isActive = value; }
        }

        public long ContentLength
        {
            get { return _contentLength; }
            set { _contentLength = value; }
        }

        #endregion

        #region Methods

        public string GetPhysicalFilePath()
        {
            HttpContext ctx = HttpContext.Current;
            string downloadFileName = ctx.Server.MapPath(string.Format("~/download/{0}.{1}", _downloadId, _extension));
            return downloadFileName;
        }

        public bool IsPhysicalFileExisting()
        {
            return File.Exists(GetPhysicalFilePath());
        }

        public bool CanBeDownloadedByCustomer(Customer thisCustomer)
        {
            bool alowCustomerToDownloadThisResource = false;

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, String.Format("SELECT * FROM EcommerceCustomerDownload with (NOLOCK) WHERE DownloadId = {0} AND Customercode = {1}", DB.SQuote(_downloadId), DB.SQuote(thisCustomer.CustomerCode))))
                {
                    alowCustomerToDownloadThisResource = reader.Read();
                }
            }

            return alowCustomerToDownloadThisResource;
        }

        public void AddCustomer(Customer thisCustomer)
        {
            DB.ExecuteSQL(String.Format("exec EcommerceAddCustomerDownload @DownloadId = {0}, @CustomerCode = {1}",
                DB.SQuote(_downloadId),
                DB.SQuote(thisCustomer.CustomerCode)
            ));
        }

        public void IncrementCustomerDownload(Customer thisCustomer)
        {
            // assume that the customer is already mapped for this downloadable item
            DB.ExecuteSQL(String.Format("UPDATE EcommerceCustomerDownload SET NumberOfDownloads = NumberOfDownloads+1 WHERE DownloadId = {0} AND CustomerCode = {1}",
                DB.SQuote(_downloadId),
                DB.SQuote(thisCustomer.CustomerCode)
            ));
        }

        public int GetNumberOfDownloads()
        {
            int numberOfDownloads = 0;

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, String.Format("SELECT SUM(NumberOfDownloads) AS NumberOfDownloads FROM EcommerceCustomerDownload with (NOLOCK) WHERE DownloadId = {0}", DB.SQuote(_downloadId))))
                {
                    if (reader.Read())
                    {
                        numberOfDownloads = DB.RSFieldInt(reader, "NumberOfDownloads");
                    }
                }
            }

            return numberOfDownloads;
        }

        private static string GenerateRandomFileName()
        {
            Guid generator = Guid.NewGuid();
            string id = generator.ToString("N");
            if (id.Length > ID_LENGTH)
            {
                return id.Substring(0, ID_LENGTH);
            }
            else
            {
                return id;
            }
        }

        public static DownloadableItem FindByItemCode(string itemCode)
        {
            return Find(itemCode, string.Empty);
        }

        public static DownloadableItem FindByDownloadId(string downloadId)
        {
            return Find(string.Empty, downloadId);
        }

        private static DownloadableItem Find(string itemCode, string downloadId)
        {
            bool exists = false;

            string whereClause = string.Empty;
            if (!string.IsNullOrEmpty(itemCode))
            {
                whereClause = string.Format(" ItemCode = {0} AND WebsiteCode = {1}", DB.SQuote(itemCode), DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode));
            }
            else if (!string.IsNullOrEmpty(downloadId))
            {
                whereClause = string.Format(" DownloadId = {0} AND WebsiteCode = {1}", DB.SQuote(downloadId), DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode));
            }
            else
            {
                throw new ArgumentNullException("Both itemcode and downloadId must be specified and cannot be null!!!");
            }

            string fileName = string.Empty;
            string extension = string.Empty;
            string contentType = string.Empty;
            long contentLength = 0;
            bool isActive = false;

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, "SELECT ItemCode, DownloadId, [FileName], Extension, ContentType, ContentLength, IsActive FROM EcommerceDownload with (NOLOCK) WHERE {0}", whereClause))
                {
                    exists = reader.Read();

                    if (exists)
                    {
                        itemCode = DB.RSField(reader, "ItemCode");
                        downloadId = DB.RSField(reader, "DownloadId");
                        fileName = DB.RSField(reader, "FileName");
                        extension = DB.RSField(reader, "Extension");
                        contentType = DB.RSField(reader, "ContentType");
                        isActive = DB.RSFieldBool(reader, "IsActive");
                        contentLength = DB.RSFieldLong(reader, "ContentLength");

                    }
                }
            }

            DownloadableItem item = null;

            if (exists)
            {
                item = new DownloadableItem(itemCode, downloadId, fileName, extension, contentType, contentLength, isActive);
            }
            else
            {
                item = null;
            }

            return item;
        }

        public static DownloadableItem MapNew(string itemCode, string fileName)
        {
            EnsureDownloadableItemExists(itemCode);

            HttpContext ctx = HttpContext.Current;
            string downloadsFolder = ctx.Server.MapPath("~/download/");
            if (!Directory.Exists(downloadsFolder)) throw new InvalidOperationException("Downloads directory missing!!!");

            string filePath = downloadsFolder + fileName;
            if (!File.Exists(filePath))
            {
                throw new ArgumentException("File not found!!!", fileName);
            }

            string downloadId = GenerateRandomFileName();

            string extension = Path.GetExtension(fileName);
            extension = extension.StartsWith(".") ? extension.Substring(1) : extension;
            string randomFileName = string.Format("{0}.{1}", downloadId, extension);
            string randomFileNameWithPath = downloadsFolder + randomFileName;

            long contentLength = 0;
            using (FileStream strm = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                contentLength = strm.Length;
            }

            string contentType = CachedMimeLookUp.Instance.GetMimeType(extension);

            // rename the file
            File.Move(filePath, randomFileNameWithPath);

            return Save(itemCode, downloadId, fileName, extension, contentType, contentLength);
        }

        private static DownloadableItem Save(string itemCode, string downloadId, string fileName, string extension, string contentType, long contentLength)
        {
            HttpContext ctx = HttpContext.Current;
            string currentlyLoggedInUser = ctx.User.Identity.Name;

            // make sure we have a valid file name format
            fileName = fileName.Replace(' ', '_');

            // update the database...
            DB.ExecuteSQL(
                "exec EcommerceSaveDownloadableItem @ItemCode = {0}, @DownloadId = {1}, @WebsiteCode = {2}, @FileName = {3}, @Extension = {4}, @ContentType = {5}, @ContentLength = {6}, @DateCreated = {7}, @UserCreated = {8}, @DateModified = {7}, @UserModified = {8}",
                DB.SQuote(itemCode),
                DB.SQuote(downloadId),
                DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode),
                DB.SQuote(fileName),
                DB.SQuote(extension),
                DB.SQuote(contentType),
                contentLength,
                DB.SQuote(Localization.ToDBDateTimeString(DateTime.Today)),
                DB.SQuote(currentlyLoggedInUser)
            );

            DownloadableItem item = new DownloadableItem(itemCode, downloadId, fileName, extension, contentType, contentLength, true);
            return item;
        }

        private static void EnsureDownloadableItemExists(string itemCode)
        {
            bool exists = false;

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, "SELECT Counter FROM InventoryItem with (NOLOCK) WHERE ItemCode = {0}", DB.SQuote(itemCode)))
                {
                    exists = reader.Read();
                }
            }

            if (!exists) throw new ElectronicDownloadException("Item does not exist!!!");
        }

        public static DownloadableItem AddNew(string itemCode, string fileName, string contentType, byte[] content)
        {
            EnsureDownloadableItemExists(itemCode);

            // first check if we already have a file existing in our table, if it has, we will replace it
            string downloadId = string.Empty;

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, "SELECT DownloadId FROM EcommerceDownload with (NOLOCK) WHERE ItemCode = {0}", DB.SQuote(itemCode)))
                {
                    if (reader.Read())
                    {
                        downloadId = DB.RSField(reader, "DownloadId");
                    }
                }
            }

            HttpContext ctx = HttpContext.Current;
            string downloadsFolder = ctx.Server.MapPath("~/download/");
            if (!Directory.Exists(downloadsFolder)) throw new InvalidOperationException("Downloads directory missing!!!");

            // empty string means it's not yet uploaded
            if (string.IsNullOrEmpty(downloadId))
            {
                downloadId = GenerateRandomFileName();
            }
            else
            {
                // remove the old file(s) to be replaced...
                DirectoryInfo downloadsDirectory = new DirectoryInfo(downloadsFolder);
                foreach (FileInfo oldFile in downloadsDirectory.GetFiles(string.Format("{0}.*", downloadId)))
                {
                    oldFile.Delete();
                }
            }

            //  insert if not yet uploaded, if already uploaded, replace the file
            //  but maintain the original extension
            string extension = Path.GetExtension(fileName);
            extension = extension.StartsWith(".") ? extension.Substring(1) : extension;
            string randomFileName = string.Format("{0}.{1}", downloadId, extension);
            string randomFileNameWithPath = downloadsFolder + randomFileName;

            // write the file
            using (FileStream strm = new FileStream(randomFileNameWithPath, FileMode.CreateNew, FileAccess.Write, FileShare.Write))
            {
                strm.Write(content, 0, content.Length);
            }

            return Save(itemCode, downloadId, fileName, extension, contentType, content.Length);
        }

        #endregion
    }

    public class ElectronicDownloadException : ApplicationException
    {
        public ElectronicDownloadException(string message)
            : base(message)
        {
        }
    }
}












